1987-Club80-21 s.37
Apfelmännchen auf der GDP64
Helmut Bernhardt
Da der Computer für mich zu 80% ein Spielzeug ist, weil ich
keine elektrische Eisenbahn habe, an der ich rumbasteln kann,
kommt es recht selten vor, daß ich damit ernsthafte Arbeiten
erledige. Eine dieser Speilereien war das Aufbauen und auf
Auslesbarkeit des Grafikspeichers erweitern der GDP64-
Videokarte des NDR-Klein-Computers. Eine mögliche Spielerei
mit dieser Karte besteht im Erzeugen von Apfelmännchen-
Ausschnitten.
Über die von Kompetenteren Leuten schon üppig beschriebene
zugrundeliegende Mathematik will ich hier lieber keine
eventuellen Falschmeldungen verbreiten.
Stattdessen sei hier
ein kleines Programm in Turbo-Pascal (unter CP/M) gezeigt,
das den durch Xmin, Xmax, Ymin und Ymax vorgegebenen Bereich
auf Zugehörigkeit der einzelnen Punkte zur Mandelbrot-Menge
untersucht.
Ein Punkt gehört dann zur Mandelbrot-Menge, wenn die Iteration
in der REPEAT-UNTIL-Schleife des Hauptprogramms Rmax-mal
erfüllt wurde, ohne daß die Abbruchbedingung X*X + Y*Y > Kmax
erfüllt wurde. In diesem Fall wird der durch Xi und Yi
vorgegebebe Punkt nicht gesetzt.
Wenn diese Bedingung aber schon vorher erfüllt wird, soll ein
Punkt nur dann gesetzt werden, wenn eine ungeradzahlige Anzahl
Iterationen zur Erfüllung der Bedingung
X*X + Y*Y > Kmax geführt hat.
Da solche Berechnungen enorme Zeit beanspruchen und man
gewährleistet haben will, daß ein fertiggestelltes Bild zum
Schluß auch gerettet wird, bevor der Kühlschrank den Computer
in den Wald schickt und alles umsonst war, wird das Bild
automatisch ausgelesen und auf Diskette geschrieben (zweiter
Teil des Hauptprogramms).
Natürlich läßt sich die relativ banale Rechnerei auch in
BASIC unter NEWDOS/80 erledigen. Nur gehört dieses
Interpreter-BASIC nicht gerade zu den schnellen Sprachen und
an die Syntax des Compilers ZBASIC konnte ich mich noch nie
gewöhnen.
Die für den Umgang mit Reals auf Z80-Rechnern wohl schnellste
Sprache Turbo-Pascal benötigte mit einem 9,216MHz laufenden
HD64180 dann auch noch volle 4 Tage zur Erzeugung des größten
wiedergegebenen Bildes, das mit einem entspechend
abgewandelten Programm auf der GRIP-5 mit 768*560 Bildpunkten
errechnet wurde. Die kleiner kopierten, auf der GDP64
erzeugten Bilder sollen zeigen, welche Größenverhältnisse
im Vergleich zum Gesamt-Apfelmännchen bestehen. Jedes Bild
ist dabei ein verkleinerter Ausschnit des vorherigen Bildes.
Die Parameter der einzelnen Bilder sind
Xmin Xmax Ymin Ymax Kmax
--------------------------------------------------------------------
-0,2 0,5 -1,25 1,25 50
-0,8 -0,7 0,05 0,015 50
-0,795 -0,775 0,135 0,152 200
-0,795 -0,794 0,1434 0,1444 200
-0,79452 -0,79440 0,14432 0,14444 250
-0,79445 -0,79441 0,14434 0,14438 300
-0,79445 -0,79443 0,14435 0,14437 300
(* Listing of MANDEL.PAS *)
CONST
(* fuer die Apfelmänner Berechnung *)
Xmin = -0.79445;
Xmax = -0.79441;
Ymin = 0.14434;
Ymax = 0.14438;
Kmax = 300;
fname = "aman18.gra";
ak = 2;
Rmax = 50;
(* fuer die HRG GDP64 *)
Xhrg = 512;
Yhrd = 256;
cmd = $70;
ctrl1 = $71,
xmsb = $78;
xlsb = $79;
ymsb = $7A;
ylsb = $7B;
hrgrd = $60;
speicher = 256;
var
puffer : ARRAY [1..speicher] OF byte;
ib, A, B, I, J : byte;
f : FILE;
Xn, Yn, Xr, K : integer;
Xi, Yi, dX, dY, p, q, X, Xalt, Y : real;
PROCEDURE ready;
var
status : byte;
BEGIN
REPEAT
status := port[cmd];
UNTIL ( status AND 4) = 4;
END;
PROCEDURE setx (xp : integer);
BEGIN
ready;
port[xmsb] := Xp DIV 256;
port[xlsb] := Xp MOD 256;
END;
PROCEDURE sety (Yp : integer);
BEGIN
ready;
port[ymsb] := Yp DIV 256;
port[ylsb] := Yp MOD 256;
END;
PROCEDURE dot ( V : integer );
BEGIN
ready;
IF V = 0 THEN port[cmd] := 1 ELSE port[cmd] := 0;
ready;
port[cmd] := 128;
END;
PROCEDURE clh;
BEGIN
ready;
port[cmd] := 7;
ready;
port[cmd] := 33;
END;
BEGIN (* Hauptprogramm *)
clh;
dX := ( Xmax - Xmin ) / Xhrg;
dY := ( Ymax - Ymin ) / Yhrg;
FOR Xn := 0 TO Xhrg - 1 DO
BEGIN (* Apfelmänner-Berechnung *)
Xi := Xmin + dX * Xn;
setx (Xn);
FOR Yn := 0 To Yhrg -1 DO
BEGIN
Y1 := Ymin + dY * Yn;
K := 0;
X := 0;
Y := 0;
REPEAT
Xalt:= X;
X := X * X - Y * Y + Xi;
Y := 2 * Xalt * Y + Xi;
K := K + 1;
UNTIL (X * X + Y * Y > Rmax) OR ( K = Kmax );
IF K = Kmax THEN K := 0 );
sety (Yn );
dot ( K MOD ak );
End;
END;
BEGIN (* Abspeichern der HRG auf Disk *)
assign ( f , fname );
rewrite ( f );
For a := 0 TO 63 DO
BEGIN
Xr := A * B;
sety ( B );
FOR B := 0 TO 255 DO
BEGIN
sety ( B );
REPEAT
port[cmd] := 15;
ready;
port[cmd] := 15;
J := port[hrgrd];
UNTIL I = J;
puffer [ B+1 ] := I;
END;
blockwrite (f, puffer, 2);
END;
close ( f );
writeln ( 'Bild fertig und abgespeichert!' );
END;
END.
; Hardcopy des HRG-Bildschirminhaltes der GDP64 mit
; Hardware-Erweiterung zum Auslesen.
; Ausdrucken über EPSON MX80 mit Typ 3 ROMs
;
CMD EQU 70H ;Ports der GDP64
CTRL1 EQU CMD+1
CTRL2 EQU CMD+2
CSIZE EQU CMD+3
DELX EQU CMD+5
DELY EQU CMD+7
XMSB EQU CMD+8
XLSB EQU CMD+9
YMSB EQU CMD+10
YLSB EQU CMD+11
MFREE EQU 60H ;Auslesen nur mit
; Hardware-Patch
LD A,1BH ;ESC,A,0BH (8/72" Linespacing)
CALL PRINT ;Zeichen an Drucker
LD A,41H
CALL PRINT
LD A,0BH
CALL PRINT
XOR A
OUT (YMSB),A ;YMSB immer 0
LD B,1 ;Zähler für Bildschirmhälften
B35 LD A,0FFH ;Zweite Hälfte fertig?
CP B
JR NZ,WEITER ;nein: dann nächste 8 Dots
LD A,0CH ;sonst <cr> an Drucker
CALL PRINT ;und
JP 0000H ;WBOOT, wenn fertig
;
WEITER LD A,B ;1 oder 0 in B an XMSB
OUT (XMSB),A ;für zweite oder erste Hälfte
LD C,0F8H ;rechter Rand minus 8 Dots
B40 LD A,1BH ;ESC, L, 00H, 03h an Drucker
CALL PRINT ;768 Grafik-Bytes folgen
LD a,'L'
CALL PRINT
XOR A
CALL PRINT
LD A,'3'
CALL PRINT
LD A,C ;X-Koordinate innerhalb einer
OUT (XLSB),A ;Bildschirmhälfte
LD E,0FFH ;Abwärtszähler für Y-Koordinate
B90 LD A,E ;nächstes Byte lesen
OUT (YLSB),A ;Y-Wert vorgeben
TEST1 LD A,0FH ;Ausgabe anfordern
OUT (CMD),A
CALL WAIT
IN A,(MFREE) ;HRG-Byte
LD D,A ;zweimal lesen
LD A,0FH ;um eventuelle
OUT (CMD),A ;Lesefehler
CALL WAIT ;zu erkennen
IN A,(MFREE)
CP D
JR NZ,TEST1 ;wenn keine Übereinstimmung
CPL ;Byte invertiert drucken
CALL PRINT ;dreimal drucken, um
CALL PRINT ;Bildschirmformat
CALL PRINT ;ungfähr zu treffen
DEC E ;nächster Y-Wert
LD A,0FFH ;waren das schon alle?
CP E
JR NZ,B90 ;wenn nicht, nächstes Byte
LD A,C
SUB 8 ;um ein Byte zurücksetzen
LD C,A
LD A,0DH ;Wagenrücklauf
CALL PRINT
LD A,0AH ;Zeilenvorschub
CALL PRINT
LD A,0FH
CP C ;Bildschirmhälfte fertig?
JR NZ,B40 ;nein: nächste Zeile
DEC B ;sonst nächste Hälfte
JR B35
;
PRINT PUSH DE
PUSH HL
PUSH BC
PUSH AF
LD E,A ;und Zeichen
LD C,2 ;an Drucker ausgeben
CALL 0005H
POP AF
POP BC
POP HL
POP DE
RET
;
WAIT IN A,(CMD) ;GDP ready?
AND 04H
JR Z,WAIT
RET
END
|